#include "xTCPTask.h"
#include <sys/ioctl.h>
#include <algorithm>
#define HANDLE_MSG_DEBUG 1
namespace xNet
{
    xTCPTask::xTCPTask(xSocket* sock)
             : m_tcpSock(sock)
             , m_state(TCP_TASK_STATE_NORMAL)
    {
    }

    xTCPTask::~xTCPTask()
    {
        if(m_tcpSock)
        {
            m_tcpSock->Close();
            DELETE(m_tcpSock);
        }
        SetState(TCP_TASK_STATE_INVAILD);
        DataPacket* pack = nullptr;
        while((pack = m_recvPacketQue.Pop()))
        {
            DELETE(pack);
        }
    }

    void xTCPTask::SendDataPacket(DataPacket& pack)
    {
        if(m_tcpSock)
        {
            SAFE_SEND_DATAPACK(m_tcpSock->GetFd(),pack)
        }
    }
    //thread safe
    bool xTCPTask::IsClose()
    {
        return m_state == TCP_TASK_STATE_EXIT;
    }

    void xTCPTask::SetState(TCP_TASK_STATE state)
    {
        m_state = state;
    }

    TCP_TASK_STATE xTCPTask::GetState()
    {
        return m_state;
    }

    bool xTCPTask::ListenRecv()
    {
        if(!SocketRead())
        {
            return false;
        }
        uint32 enReadSize = m_recvByteBuffer.ReadSize();
        const uint8* readBegin = m_recvByteBuffer.ReadBegin();
        
#if     HANDLE_MSG_DEBUG
        uint32 parseSize = enReadSize;
        DataPacket* pack = new DataPacket(0);
        pack->ReSize(enReadSize);
        memcpy(pack->WriteBegin(),readBegin,enReadSize);
        pack->AddWPos(enReadSize);
        m_recvPacketQue.Push(pack);
        //::send(GetTCPSock()->GetFd(),readBegin,enReadSize,0);
        //std::cout << "send echo msg success" << std::endl; 
#else
        uint32 parseSize = 0;
        while(1)
        {
            if(enReadSize < MIN_DATA_PACKAGE_SIZE)
            {
                break;
            }
            uint32 packSize = 0;
            memcpy(&packSize,readBegin,sizeof(packSize));    
            if(packSize > MAX_DATA_PACKAGE_SIZE)
            {
                SetState(TCP_TASK_STATE_RECYCLE);
                return false;
            }
            else if(packSize > enReadSize)
            {
                break;
            }
            uint16 opcode = 0;
            memcpy(&opcode,readBegin+sizeof(uint32),sizeof(uint16));
            if(!VaildOpCode(opcode))
            {
                SetState(TCP_TASK_STATE_RECYCLE);
                return false;
            }
            DataPacket* pack = new DataPacket(opcode);
            pack->ReSize(packSize);
            uint8 headerSize = sizeof(uint32) + sizeof(uint16);
            memcpy(pack->WriteBegin(),readBegin+headerSize,packSize-headerSize);
            pack->AddWPos(packSize-headerSize);

            m_recvPacketQue.Push(pack);

            parseSize += packSize;
            readBegin += packSize;
            enReadSize -= packSize;
        }
#endif
        m_recvByteBuffer.AddRPos(parseSize);
        return true;
    }

    bool xTCPTask::ListenSend()
    {
        return true;
    }

    int xTCPTask::SocketRead()
    {
        unsigned long maxPacketSize = MAX_DATA_PACKAGE_SIZE;
        if(ioctl(m_tcpSock->GetFd(),FIONREAD,&maxPacketSize) == -1 || maxPacketSize == 0)
        {
            maxPacketSize = MAX_DATA_PACKAGE_SIZE;
        }
        maxPacketSize = maxPacketSize > MAX_DATA_PACKAGE_SIZE ? MAX_DATA_PACKAGE_SIZE : maxPacketSize;
        m_recvByteBuffer.Expand(maxPacketSize);
        void* writeBegin = static_cast<void*>(m_recvByteBuffer.WriteBegin());
        if(!m_tcpSock->RecvData(writeBegin,maxPacketSize))
        {
            SetState(TCP_TASK_STATE_RECYCLE);
            return 0;
        }
        m_recvByteBuffer.AddWPos(maxPacketSize);
        return maxPacketSize;
    }
}